package handling.channel;

import client.MapleCharacter;
import client.MapleClient;
import constants.ServerConfig;
import constants.WorldConstants;
import gui.Start;
import handling.cashshop.CashShopServer;
import handling.login.LoginServer;
import handling.mina.ServerConnection;
import handling.world.CheaterData;
import scripting.EventScriptManager;
import server.MapleSquad;
import server.MapleSquad.MapleSquadType;
import server.ServerProperties;
import server.events.*;
import server.life.PlayerNPC;
import server.maps.MapleMapFactory;
import server.maps.MapleMapObject;
import server.shops.HiredMerchant;
import server.shops.HiredMerchantSave;
import server.shops.MaplePlayerShop;
import tools.CollectionUtil;
import tools.ConcurrentEnumMap;
import tools.FileoutputUtil;
import tools.MaplePacketCreator;

import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ChannelServer implements Serializable {
    public static long serverStartTime;
    private short port;
    private static short DEFAULT_PORT = 7575;
    private int channel;
    private int running_MerchantID;
    private int running_PlayerShopID;
    private String socket;
    private boolean shutdown;
    private boolean finishedShutdown;
    private boolean MegaphoneMuteState;
    private PlayerStorage players;
    private ServerConnection acceptor;
    private MapleMapFactory mapFactory;
    private EventScriptManager eventSM;
    private EventScriptManager eventSMA;
    private EventScriptManager eventSMB;
    private EventScriptManager eventSMC;
    private static Map<Integer, ChannelServer> instances;
    private Map<MapleSquadType, MapleSquad> mapleSquads;
    private Map<Integer, HiredMerchant> merchants;
    private Map<Integer, MaplePlayerShop> playershops;
    private Map<Integer, PlayerNPC> playerNPCs;
    private ReentrantReadWriteLock merchLock;
    private ReentrantReadWriteLock squadLock;
    private int eventmap;
    private Map<MapleEventType, MapleEvent> events;
    private static String 初始ip;

    private ChannelServer(int channel) {
        this.port = 7575;
        this.running_MerchantID = 0;
        this.running_PlayerShopID = 0;
        this.shutdown = false;
        this.finishedShutdown = false;
        this.MegaphoneMuteState = false;
        this.mapleSquads = new ConcurrentEnumMap(MapleSquadType.class);
        this.merchants = (Map<Integer, HiredMerchant>) new HashMap();
        this.playershops = (Map<Integer, MaplePlayerShop>) new HashMap();
        this.playerNPCs = (Map<Integer, PlayerNPC>) new HashMap();
        this.merchLock = new ReentrantReadWriteLock();
        this.squadLock = new ReentrantReadWriteLock();
        this.eventmap = -1;
        this.events = new EnumMap(MapleEventType.class);
        this.channel = channel;
        (this.mapFactory = new MapleMapFactory()).setChannel(channel);
    }

    public static Set<Integer> getAllChannels() {
        return new HashSet(ChannelServer.instances.keySet());
    }

    public void loadEvents() {
        if (!this.events.isEmpty()) {
            return;
        }
        this.events.put(MapleEventType.打瓶盖, new MapleCoconut(this.channel, MapleEventType.打瓶盖.mapids));
        this.events.put(MapleEventType.打果子, new MapleCoconut(this.channel, MapleEventType.打果子.mapids));
        this.events.put(MapleEventType.终极忍耐, new MapleFitness(this.channel, MapleEventType.终极忍耐.mapids));
        this.events.put(MapleEventType.爬绳子, new MapleOla(this.channel, MapleEventType.爬绳子.mapids));
        this.events.put(MapleEventType.是非题大考验, new MapleOxQuiz(this.channel, MapleEventType.是非题大考验.mapids));
        this.events.put(MapleEventType.滚雪球, new MapleSnowball(this.channel, MapleEventType.滚雪球.mapids));
        this.events.put(MapleEventType.寻宝, new MapleJewel(this.channel, MapleEventType.寻宝.mapids));
    }

    public void setup() {
        this.setChannel(this.channel);
        try {
            this.eventSM = new EventScriptManager(this, ServerProperties.getProperty("cc.events").split(","));
            this.port = (short) (ServerProperties.getProperty("cc.ChannelPort", (short) 7575) + this.channel - 1);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        this.socket = ChannelServer.初始ip + ":" + (int) this.port;
        this.players = new PlayerStorage(this.channel);
        this.loadEvents();
        (this.acceptor = new ServerConnection((int) this.port, 0, this.channel)).run();
        System.out.println("[" + FileoutputUtil.CurrentReadable_Time() + "][信息]:频道" + this.getChannel() + ".    - 监听端口: " + (int) this.port + "");
        this.eventSM.init();
    }

    public void shutdown() {
        if (this.finishedShutdown) {
            return;
        }
        this.broadcastPacket(MaplePacketCreator.serverNotice(0, "【频道" + this.getChannel() + "】 这个频道正在关闭中."));
        this.shutdown = true;
        System.out.println("[" + FileoutputUtil.CurrentReadable_Time() + "][信息]:[频道" + this.getChannel() + "] 储存角色资料");
        System.out.println("[" + FileoutputUtil.CurrentReadable_Time() + "][信息]:[频道" + this.getChannel() + "] 解除端口綁定中");
        try {
            if (this.acceptor != null) {
                this.acceptor.close();
                System.out.println("[" + FileoutputUtil.CurrentReadable_Time() + "][信息]:[频道" + this.getChannel() + "] 解除端口成功");
            }
        } catch (Exception e) {
            System.out.println("[" + FileoutputUtil.CurrentReadable_Time() + "][信息]:[频道" + this.getChannel() + "] 解除端口失败" + e);
        }
        ChannelServer.instances.remove(Integer.valueOf(this.channel));
        LoginServer.removeChannel(this.channel);
        this.setFinishShutdown();
    }

    public boolean hasFinishedShutdown() {
        return this.finishedShutdown;
    }

    public MapleMapFactory getMapFactory() {
        return this.mapFactory;
    }

    public void addPlayer(MapleCharacter chr) {
        this.getPlayerStorage().registerPlayer(chr);
        chr.getClient().sendPacket(MaplePacketCreator.serverMessage(this.getServerMessage()));
    }

    public PlayerStorage getPlayerStorage() {
        if (this.players == null) {
            this.players = new PlayerStorage(this.channel);
        }
        return this.players;
    }

    public void removePlayer(MapleCharacter chr) {
        this.getPlayerStorage().deregisterPlayer(chr);
    }

    public void removePlayer(int idz, String namez) {
        this.getPlayerStorage().deregisterPlayer(idz, namez);
    }

    public String getServerMessage() {
        return WorldConstants.SCROLL_MESSAGE;
    }

    public void setServerMessage(String newMessage) {
        WorldConstants.SCROLL_MESSAGE = newMessage;
    }

    public void broadcastPacket(byte[] data) {
        this.getPlayerStorage().broadcastPacket(data);
    }

    public void broadcastSmegaPacket(byte[] data) {
        this.getPlayerStorage().broadcastSmegaPacket(data);
    }

    public void broadcastGashponmegaPacket(byte[] data) {
        this.getPlayerStorage().broadcastGashponmegaPacket(data);
    }

    public void broadcastGMPacket(byte[] data) {
        this.getPlayerStorage().broadcastGMPacket(data);
    }

    public void broadcastGMPacket(byte[] data, boolean 吸怪) {
        this.getPlayerStorage().broadcastGMPacket(data, 吸怪);
    }

    public int getExpRate() {
        return WorldConstants.EXP_RATE;
    }

    public void setExpRate(int expRate) {
        WorldConstants.EXP_RATE = expRate;
    }

    public int getMesoRate() {
        return WorldConstants.MESO_RATE;
    }

    public void setMesoRate(int mesoRate) {
        WorldConstants.MESO_RATE = mesoRate;
    }

    public int getDropRate() {
        return WorldConstants.DROP_RATE;
    }

    public void setDropRate(int dropRate) {
        WorldConstants.DROP_RATE = dropRate;
    }

    public int getChannel() {
        return this.channel;
    }

    public void setChannel(int channel) {
        ChannelServer.instances.put(Integer.valueOf(channel), this);
        LoginServer.addChannel(channel);
    }

    public static Collection<ChannelServer> getAllInstances() {
        return Collections.unmodifiableCollection(ChannelServer.instances.values());
    }

    public String getSocket() {
        return this.socket;
    }

    public boolean isShutdown() {
        return this.shutdown;
    }

    public int getLoadedMaps() {
        return this.mapFactory.getLoadedMaps();
    }

    public EventScriptManager getEventSM() {
        return this.eventSM;
    }

    public EventScriptManager getEventSMA() {
        return this.eventSMA;
    }

    public EventScriptManager getEventSMB() {
        return this.eventSMB;
    }

    public EventScriptManager getEventSMC() {
        return this.eventSMC;
    }

    public void reloadEvents() {
        this.eventSM.cancel();
        (this.eventSM = new EventScriptManager(this, ServerProperties.getProperty("cc.events").split(","))).init();
    }

    public void reloadEventsa() {
        this.eventSMA.cancel();
        (this.eventSMA = new EventScriptManager(this, ServerProperties.getProperty("cc.活动事件脚本").split(","))).init();
    }

    public void reloadEventsb() {
        this.eventSMB.cancel();
        (this.eventSMB = new EventScriptManager(this, ServerProperties.getProperty("cc.BOSS事件脚本").split(","))).init();
    }

    public void reloadEventsc() {
        this.eventSMC.cancel();
        (this.eventSMC = new EventScriptManager(this, ServerProperties.getProperty("cc.自定义事件脚本").split(","))).init();
    }

    public Map<MapleSquadType, MapleSquad> getAllSquads() {
        return Collections.unmodifiableMap(this.mapleSquads);
    }

    public MapleSquad getMapleSquad(String type) {
        return this.getMapleSquad(MapleSquadType.valueOf(type.toLowerCase()));
    }

    public MapleSquad getMapleSquad(MapleSquadType type) {
        return (MapleSquad) this.mapleSquads.get(type);
    }

    public boolean addMapleSquad(MapleSquad squad, String type) {
        MapleSquadType types = MapleSquadType.valueOf(type.toLowerCase());
        if (types != null && !this.mapleSquads.containsKey(types)) {
            this.mapleSquads.put(types, squad);
            squad.scheduleRemoval();
            return true;
        }
        return false;
    }

    public boolean removeMapleSquad(MapleSquadType types) {
        if (types != null && this.mapleSquads.containsKey(types)) {
            this.mapleSquads.remove(types);
            return true;
        }
        return false;
    }

    public int closeAllPlayerShop() {
        int ret = 0;
        this.merchLock.writeLock().lock();
        try {
            Iterator<Entry<Integer, MaplePlayerShop>> playershops_ = this.playershops.entrySet().iterator();
            while (playershops_.hasNext()) {
                MaplePlayerShop hm = (MaplePlayerShop) ((Entry<Integer, MaplePlayerShop>) playershops_.next()).getValue();
                hm.closeShop(true, false);
                hm.getMap().removeMapObject((MapleMapObject) hm);
                playershops_.remove();
                ++ret;
            }
        }
        finally {
            this.merchLock.writeLock().unlock();
        }
        return ret;
    }

    public int closeAllMerchant() {
        int ret = 0;
        this.merchLock.writeLock().lock();
        try {
            Iterator<Entry<Integer, HiredMerchant>> merchants_ = this.merchants.entrySet().iterator();
            while (merchants_.hasNext()) {
                HiredMerchant hm = (HiredMerchant) ((Entry<Integer, HiredMerchant>) merchants_.next()).getValue();
                hm.closeShop(true, false);
                HiredMerchantSave.QueueShopForSave(hm);
                hm.getMap().removeMapObject((MapleMapObject) hm);
                merchants_.remove();
                ++ret;
            }
        }
        finally {
            this.merchLock.writeLock().unlock();
        }
        for (int i = 910000001; i <= 910000022; ++i) {
            for (MapleMapObject mmo : this.mapFactory.getMap(i).getAllHiredMerchantsThreadsafe()) {
                HiredMerchantSave.QueueShopForSave((HiredMerchant) mmo);
                ((HiredMerchant) mmo).closeShop(true, false);
                ++ret;
            }
        }
        return ret;
    }

    public int addPlayerShop(MaplePlayerShop PlayerShop) {
        this.merchLock.writeLock().lock();
        int runningmer = 0;
        try {
            runningmer = this.running_PlayerShopID;
            this.playershops.put(Integer.valueOf(this.running_PlayerShopID), PlayerShop);
            ++this.running_PlayerShopID;
        }
        finally {
            this.merchLock.writeLock().unlock();
        }
        return runningmer;
    }

    public int addMerchant(HiredMerchant hMerchant) {
        this.merchLock.writeLock().lock();
        int runningmer = 0;
        try {
            runningmer = this.running_MerchantID;
            this.merchants.put(Integer.valueOf(this.running_MerchantID), hMerchant);
            ++this.running_MerchantID;
        }
        finally {
            this.merchLock.writeLock().unlock();
        }
        return runningmer;
    }

    public void removeMerchant(HiredMerchant hMerchant) {
        this.merchLock.writeLock().lock();
        try {
            this.merchants.remove(Integer.valueOf(hMerchant.getStoreId()));
        }
        finally {
            this.merchLock.writeLock().unlock();
        }
    }

    public boolean containsMerchant(int accid) {
        boolean contains = false;
        this.merchLock.readLock().lock();
        try {
            Iterator itr = this.merchants.values().iterator();
            while (itr.hasNext()) {
                if (((HiredMerchant) itr.next()).getOwnerAccId() == accid) {
                    contains = true;
                    break;
                }
            }
        }
        finally {
            this.merchLock.readLock().unlock();
        }
        return contains;
    }

    public List<HiredMerchant> searchMerchant(int itemSearch) {
        List<HiredMerchant> list = (List<HiredMerchant>) new LinkedList();
        this.merchLock.readLock().lock();
        try {
            for (HiredMerchant hm : this.merchants.values()) {
                if (hm.searchItem(itemSearch).size() > 0) {
                    list.add(hm);
                }
            }
        }
        finally {
            this.merchLock.readLock().unlock();
        }
        return list;
    }

    public void toggleMegaphoneMuteState() {
        this.MegaphoneMuteState = !this.MegaphoneMuteState;
    }

    public boolean getMegaphoneMuteState() {
        return this.MegaphoneMuteState;
    }

    public int getEvent() {
        return this.eventmap;
    }

    public void setEvent(int ze) {
        this.eventmap = ze;
    }

    public MapleEvent getEvent(MapleEventType t) {
        return (MapleEvent) this.events.get(t);
    }

    public Collection<PlayerNPC> getAllPlayerNPC() {
        return this.playerNPCs.values();
    }

    public PlayerNPC getPlayerNPC(int id) {
        return (PlayerNPC) this.playerNPCs.get(Integer.valueOf(id));
    }

    public void addPlayerNPC(PlayerNPC npc) {
        if (this.playerNPCs.containsKey(Integer.valueOf(npc.getId()))) {
            this.removePlayerNPC(npc);
        }
        this.playerNPCs.put(Integer.valueOf(npc.getId()), npc);
        this.getMapFactory().getMap(npc.getMapId()).addMapObject((MapleMapObject) npc);
    }

    public void removePlayerNPC(PlayerNPC npc) {
        if (this.playerNPCs.containsKey(Integer.valueOf(npc.getId()))) {
            this.playerNPCs.remove(Integer.valueOf(npc.getId()));
            this.getMapFactory().getMap(npc.getMapId()).removeMapObject((MapleMapObject) npc);
        }
    }

    public String getServerName() {
        return ServerConfig.SERVER_NAME;
    }

    public void setServerName(String sn) {
        ServerConfig.SERVER_NAME = sn;
    }

    public int getPort() {
        return this.port;
    }

    public void setPrepareShutdown() {
        this.shutdown = true;
        System.out.println("[" + FileoutputUtil.CurrentReadable_Time() + "][信息]:[频道" + this.getChannel() + "] 正在准备关闭");
    }

    public void setFinishShutdown() {
        this.finishedShutdown = true;
        System.out.println("[" + FileoutputUtil.CurrentReadable_Time() + "][信息]:[频道" + this.getChannel() + "] 已经关闭完毕");
    }

    public boolean isAdminOnly() {
        return WorldConstants.ADMIN_ONLY;
    }

    public static Map<Integer, Integer> getChannelLoad() {
        Map<Integer, Integer> ret = (Map<Integer, Integer>) new HashMap();
        for (ChannelServer cs : ChannelServer.instances.values()) {
            ret.put(Integer.valueOf(cs.getChannel()), Integer.valueOf(cs.getConnectedClients()));
        }
        return ret;
    }

    public int getConnectedClients() {
        double bfb = (double) LoginServer.getRSGS() / 100.0 * (double) this.getPlayerStorage().getConnectedClients();
        return this.getPlayerStorage().getConnectedClients() + (int) Math.ceil(bfb);
    }

    public List<CheaterData> getCheaters() {
        List<CheaterData> cheaters = this.getPlayerStorage().getCheaters();
        Collections.sort(cheaters);
        return CollectionUtil.copyFirst(cheaters, 20);
    }

    public void broadcastMessage(byte[] message) {
        this.broadcastPacket(message);
    }

    public void broadcastSmega(byte[] message) {
        this.broadcastSmegaPacket(message);
    }

    public void broadcastGashponmega(byte[] message) {
        this.broadcastGashponmegaPacket(message);
    }

    public void broadcastGMMessage(byte[] message, boolean 吸怪) {
        this.broadcastGMPacket(message, 吸怪);
    }

    public void broadcastGMMessage(byte[] message) {
        this.broadcastGMPacket(message);
    }

    public void saveAll() {
        int ppl = 0;
        List<MapleCharacter> all = this.players.getAllCharactersThreadSafe();
        for (MapleCharacter chr : all) {
            try {
                int res = chr.saveToDB(false, false);
                if (((Integer) Start.ConfigValuesMap.get("离线泡点开关")).intValue() > 0) {
                    chr.updateOfflineTime();
                }
                if (res == 1) {
                    ++ppl;
                } else {
                    System.out.println("[自动存档] 角色:" + chr.getName() + " 储存失败.");
                }
            } catch (Exception e) {
                FileoutputUtil.logToFile("logs/saveAll存档保存数据异常.txt", "\r\n " + FileoutputUtil.NowTime() + " IP: " + chr.getClient().getSession().remoteAddress().toString().split(":")[0] + " 账号 " + chr.getClient().getAccountName() + " 账号ID " + chr.getClient().getAccID() + " 角色名 " + chr.getName() + " 角色ID " + chr.getId());
                FileoutputUtil.outError("logs/saveAll存档保存数据异常.txt", (Throwable) e);
            }
        }
    }

    public boolean CanGMItem() {
        return WorldConstants.GMITEMS;
    }

    public int getMerchantMap(MapleCharacter chr) {
        int ret = -1;
        for (int i = 910000001; i <= 910000022; ++i) {
            for (MapleMapObject mmo : this.mapFactory.getMap(i).getAllHiredMerchantsThreadsafe()) {
                if (((HiredMerchant) mmo).getOwnerId() == chr.getId()) {
                    return this.mapFactory.getMap(i).getId();
                }
            }
        }
        return ret;
    }

    public static int getChannelCount() {
        return ChannelServer.instances.size();
    }

    public static void forceRemovePlayerByAccId(MapleClient client, int accid) {
        for (ChannelServer ch : getAllInstances()) {
            Collection<MapleCharacter> chrs = ch.getPlayerStorage().getAllCharactersThreadSafe();
            for (MapleCharacter c : chrs) {
                if (c.getAccountID() == accid) {
                    try {
                        if (c.getClient() != null && c.getClient() != client) {
                            c.getClient().unLockDisconnect();
                        }
                    } catch (Exception ex) {
                    }
                    chrs = ch.getPlayerStorage().getAllCharactersThreadSafe();
                    if (!chrs.contains(c)) {
                        continue;
                    }
                    ch.removePlayer(c);
                }
            }
        }
        try {
            Collection<MapleCharacter> chrs2 = CashShopServer.getPlayerStorage().getAllCharactersThreadSafe();
            for (MapleCharacter c2 : chrs2) {
                if (c2.getAccountID() == accid) {
                    try {
                        if (c2.getClient() == null || c2.getClient() == client) {
                            continue;
                        }
                        c2.getClient().unLockDisconnect();
                    } catch (Exception ex2) {
                    }
                }
            }
        } catch (Exception ex3) {
        }
    }

    public static Set<Integer> getChannels() {
        return new HashSet(ChannelServer.instances.keySet());
    }

    public static ChannelServer newInstance(int channel) {
        return new ChannelServer(channel);
    }

    public static ChannelServer getInstance(int channel) {
        return (ChannelServer) ChannelServer.instances.get(Integer.valueOf(channel));
    }

    public static void startAllChannels() {
        ChannelServer.serverStartTime = System.currentTimeMillis();
        for (int channelCount = WorldConstants.CHANNEL_COUNT, i = 1; i <= Math.min(20, (channelCount > 0) ? channelCount : 1); ++i) {
            newInstance(i).setup();
        }
    }

    public static void startChannel(int channel) {
        ChannelServer.serverStartTime = System.currentTimeMillis();
        if (channel <= WorldConstants.CHANNEL_COUNT) {
            newInstance(channel).setup();
        }
    }

    public static void forceRemovePlayerByCharName(MapleClient client, String Name) {
        for (ChannelServer ch : getAllInstances()) {
            Collection<MapleCharacter> chrs = ch.getPlayerStorage().getAllCharactersThreadSafe();
            for (MapleCharacter c : chrs) {
                if (c.getName().equalsIgnoreCase(Name)) {
                    try {
                        if (c.getClient() != null && c.getClient() != client) {
                            c.getClient().unLockDisconnect();
                        }
                    } catch (Exception ex) {
                    }
                    chrs = ch.getPlayerStorage().getAllCharactersThreadSafe();
                    if (chrs.contains(c)) {
                        ch.removePlayer(c);
                    }
                    c.getMap().removePlayer(c);
                }
            }
        }
    }

    public static void forceRemovePlayerByCharNameFromDataBase(MapleClient client, List<String> Name) {
        for (ChannelServer ch : getAllInstances()) {
            for (String name : Name) {
                if (ch.getPlayerStorage().getCharacterByName(name) != null) {
                    MapleCharacter c = ch.getPlayerStorage().getCharacterByName(name);
                    try {
                        if (c.getClient() != null && c.getClient() != client) {
                            c.getClient().unLockDisconnect();
                        }
                    } catch (Exception ex) {
                    }
                    if (ch.getPlayerStorage().getAllCharactersThreadSafe().contains(c)) {
                        ch.removePlayer(c);
                    }
                    c.getMap().removePlayer(c);
                }
            }
        }
        for (String name2 : Name) {
            if (CashShopServer.getPlayerStorage().getCharacterByName(name2) != null) {
                MapleCharacter c2 = CashShopServer.getPlayerStorage().getCharacterByName(name2);
                try {
                    if (c2.getClient() == null || c2.getClient() == client) {
                        continue;
                    }
                    c2.getClient().unLockDisconnect();
                } catch (Exception ex2) {
                }
            }
        }
    }

    public void AutoNx(int dy) {
        this.mapFactory.getMap(910000000).AutoNxmht(dy);
    }

    public void AutoTime(int dy) {
        for (ChannelServer chan : getAllInstances()) {
            for (MapleCharacter chr : chan.getPlayerStorage().getAllCharacters()) {
                if (chr != null) {
                    chr.gainGamePoints(1);
                    if (chr.getGamePoints() >= 5) {
                        continue;
                    }
                    chr.resetGamePointsPD();
                }
            }
        }
    }

    static {
        instances = new HashMap();
        初始ip = ServerProperties.getProperty("cc.IPAddress");
    }
}
